﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace schedule
{
    class BoundedDEQueue<T> : schedule.IDEQueue<T>
    {
        T[] tasks;
        public volatile int bottom;
        public int top;
        
        public bool isFull
        {
            get { return tasks.Length == bottom; }
        }

        public BoundedDEQueue(int capacity)
        {
            tasks = new T[capacity];
            top = 0;
            bottom = 0;
        }

        void IDEQueue<T>.pushBottom(T obj)
        {
            try
            {
                tasks[bottom++] = obj;
            }
            catch
            {
                --bottom;
            }
        }

        bool IDEQueue<T>.isEmpty()
        {
            return top >= bottom;
        }

        T IDEQueue<T>.popTop()
        {
            int oldTop = top, newTop = oldTop + 1;

            if (bottom <= top)
                return default(T);

            T obj = tasks[oldTop];
            if (Interlocked.CompareExchange(ref top, newTop, oldTop) == oldTop)
                return obj;
            return default(T);
        }

        T IDEQueue<T>.popBottom()
        {
            if (bottom == 0)
                return default(T);

            --bottom;
            T obj = tasks[bottom];
            int oldTop = top, newTop = 0;
            if (bottom > oldTop)
                return obj;

            if (bottom == oldTop)
            {
                bottom = 0;

                if (Interlocked.CompareExchange(ref top, oldTop, newTop) == oldTop)
                    return obj;
            }

            Interlocked.Exchange(ref top, newTop);
            return default(T);
        }
    }
}
